package it.poli.IA.TilesGame;

import java.util.Comparator;

import it.poli.IA.exceptions.UndefinedComparatorException;
import it.poli.IA.space.Node;

public class TileNode extends Node implements Cloneable
{
	
	public TileNode(TileState currentState, TileAction pastAction, TileNode parentNode,  int totalCost)
	{
		this.currentState = currentState;
		this.pastAction = pastAction;
		this.parentNode = parentNode;
		this.totalCost = totalCost;
	}
	
	private CostFunction tileComparator;
	
	/**
	 * root
	 */
	public TileNode( TileState currentState)
	{
		this.currentState = currentState;
		this.pastAction = null;
		this.parentNode = null;
		this.totalCost = 0;
	}
	
	
	
	@Override
	public int hashCode() {
		final int prime = 31;
		int result = 1;
		result = prime * result
				+ ((currentState == null) ? 0 : currentState.hashCode());
		result = prime * result
				+ ((parentNode == null) ? 0 : parentNode.hashCode());
		result = prime * result
				+ ((pastAction == null) ? 0 : pastAction.hashCode());
		result = prime * result
				+ ((totalCost == null) ? 0 : totalCost.hashCode());
		return result;
	}
	@Override
	public boolean equals(Object obj) {
		if (this == obj) {
			return true;
		}
		if (obj == null) {
			return false;
		}
		if (!(obj instanceof TileNode)) {
			return false;
		}
		TileNode other = (TileNode) obj;
		if (currentState == null)
		{
			if (other.currentState != null) 
			{
				return false;
			}
		} 
		else if (!currentState.equals(other.currentState))
		{
			return false;
		}
		
		if (parentNode == null) {
			if (other.parentNode != null) 
			{
				return false;
			}
		} 
		else if (!parentNode.equals(other.parentNode))
		{
			return false;
		}
		
		if (pastAction != other.pastAction)
		{
			return false;
		}
		
		if (totalCost == null) {
			if (other.totalCost != null) 
			{
				return false;
			}
		} 
		else if (!totalCost.equals(other.totalCost)) 
		{
			return false;
		}
		return true;
	}


	@Override
	public Comparator<? super Node> getComparator() throws UndefinedComparatorException 
	{
		Comparator<Node> cn = new Comparator<Node>() {
			
			@Override
			public int compare(Node o1, Node o2)
			{
				if(o1.getCurrentState() instanceof TileState == false || o2.getCurrentState() instanceof TileState ==false)
					return 0;
				else
				{
					if(TileState.useSumOfDistance == true)
						return compareSumOfDistances((TileState)o1.getCurrentState(), (TileState)o2.getCurrentState());
					else
						return compareMisplaced( (TileState)o1.getCurrentState(), (TileState)o2.getCurrentState() );
				
				}
			}

			private int compareSumOfDistances(TileState state1,
					TileState state2) {
				Double sumOfDist1 = sumOfDistance(state1);
				Double sumOfDist2 = sumOfDistance(state2);
				return sumOfDist1.compareTo(sumOfDist2);
			}



		};
		
		return cn;
		
	}
	
	private double sumOfDistance(TileState givenState) {
		
		return givenState.getSumOfDistance(givenState);
		
	}

	private int compareMisplaced(TileState ts1, TileState ts2) {
		
		Integer misplaced1 = this.getMisplaced(ts1);
		Integer misplaced2 = this.getMisplaced(ts2);
		
		return misplaced1.compareTo(misplaced2);
	
	}
	

	private Integer getMisplaced(TileState ts) {
		return ts.numberOfMisplacedTiles();
		
	}

	@Override
	public String toString() {
		return "Node [currentState=" + currentState + ", totalCost="
				+ totalCost + "]";
	}



	public CostFunction getTileComparator() {
		return tileComparator;
	}



	public void setTileComparator(CostFunction tileComparator) {
		this.tileComparator = tileComparator;
	}

	
	
	
}
